package top.codedance.iotp.client.plugins.sync.udp;

import com.alibaba.fastjson.JSONObject;
import top.codedance.iotp.client.ClientApplication;
import top.codedance.iotp.common.executer.SyncAbstractExecuter;
import top.codedance.iotp.common.entity.PluginResultEntity;
import top.codedance.iotp.common.util.BytesBuilder;
import org.apache.log4j.Logger;

import javax.xml.bind.DatatypeConverter;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class UdpExecuterImpl extends SyncAbstractExecuter {
    private Logger logger = ClientApplication.getLogger(UdpExecuterImpl.class);
    public static ExecutorService pluginServiceWorkerPool = Executors.newCachedThreadPool(); //插件服务线程池
    public static volatile Map<Integer, UdpClient> clients = new HashMap<>();
    private BytesBuilder currentData = new BytesBuilder();
    private CountDownLatch latch = new CountDownLatch(1);

    public synchronized PluginResultEntity exec(byte[] data, String taskId) {
        PluginResultEntity result = null;
        try {
            String str = new String(data, StandardCharsets.UTF_8);
            JSONObject client = JSONObject.parseObject(str);
            Integer clientId = client.getInteger("id");
            String command = client.getString("command");
            boolean isHex = false;
            if(client.containsKey("hex")){
                isHex = client.getBoolean("hex");
            }
            if(!clients.containsKey(clientId)){
                UdpClient uc = new UdpClient(this, clientId, getIniConfig());
                pluginServiceWorkerPool.submit(uc);
                Thread.sleep(1000);
            }
            UdpClient uc = clients.get(clientId);
            byte[] cmdBytes;
            if(isHex){
                cmdBytes = DatatypeConverter.parseHexBinary(command);
            }else{
                cmdBytes = command.getBytes();
            }
            uc.send(cmdBytes);
            boolean await = latch.await(2, TimeUnit.SECONDS);
            if (await) {
                latch = new CountDownLatch(1);
                String d = DatatypeConverter.printHexBinary(currentData.toArray());
                result = new PluginResultEntity();
                result.setOk(true);
                result.setContext(d);
                result.setHex("context");
                currentData = new BytesBuilder();
            }
        }catch (Exception e){
            logger.debug(e.getMessage());
            result = new PluginResultEntity();
            result.setOk(false);
            result.setMsg(e.getMessage());
        }
        if(result == null){
            result = new PluginResultEntity();
            result.setOk(true);
            result.setMsg("The current return value is empty. If the command expects a return value, please check the correctness of the command!");
        }
        return result;
    }

    public void appendResult(byte[] data){
        currentData.append(data);
        latch.countDown();
    }
}
